package com.hospital.hospitalsystem.modules.login.biz;

import com.alibaba.fastjson.JSONObject;
import com.hospital.hospitalsystem.config.HospitalProperties;
import com.hospital.hospitalsystem.modules.login.dao.entity.*;
import com.hospital.hospitalsystem.modules.login.dto.*;
import com.hospital.hospitalsystem.modules.login.service.*;
import com.hospital.hospitalsystem.utils.SendEmailUtils;
import com.hospital.hospitalsystem.utils.SendVerificationCodeUtils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.impl.DefaultClaims;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import tk.mybatis.mapper.entity.Example;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author qiancheng@cqxyy.net
 * @date 2023/2/22
 */
@Service
public class LoginBiz {

    @Autowired
    private HospitalProperties hospitalProperties;

    @Autowired
    private DoctorService doctorService;

    @Autowired
    private UserService userService;

    @Autowired
    private UserMessageService userMessageService;

    @Autowired
    private HospitalMessageService hospitalMessageService;

    @Autowired
    private HospitalRegisterService hospitalRegisterService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private HospitalProperties giftProperties;

    @Autowired
    private SendEmailUtils sendEmails;

    //token密钥
    private static final String TOKEN_SECRET = "LJSBF932GFH9WF9WEGFFGWEPUFWPUFG3Q3D";

    //设置过期时间
    private static final long EXPIRE_DATE = 30*60*10000;
    /**
     * 用户注册
     * @param req
     */
    public void userRegister(UserRegisterReq req) {
        Example example = new Example(UserMessageEntity.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("email",req.getEmail()).orEqualTo("phone",req.getPhone());
        List<UserMessageEntity> userCheck = userMessageService.selectByExample(example);
        if (CollectionUtils.isNotEmpty(userCheck)){
            if (userCheck.get(0).getEmail().equals(req.getEmail())){
                throw new RuntimeException("此邮箱已被注册");
            }
            if (userCheck.get(0).getPhone().equals(req.getPhone())){
                throw new RuntimeException("此手机号已被注册");
            }
        }
        checkVerify(req.getEmail(),req.getVerify());
        UserEntity user = new UserEntity();
        String userUuid = UUID.randomUUID().toString();
        user.setUuid(userUuid);
        user.setAccount(req.getEmail());
        user.setPassword(req.getPassword());
        user.setType("user");
        userService.insertSelective(user);

        UserMessageEntity userMessageEntity = new UserMessageEntity();
        BeanUtils.copyProperties(req,userMessageEntity);
        userMessageEntity.setUuid(userUuid);
        userMessageService.insertSelective(userMessageEntity);
    }

    /**
     * 发送电子邮箱
     * @param req
     */
    public void sendEmail(SendEmailReq req) {
        String verification = SendVerificationCodeUtils.getVerificationCode();
        redisTemplate.opsForValue().set(req.getEmail(),verification,giftProperties.getOverTime(), TimeUnit.MINUTES);
        EmailEntityExt emailEntity = new EmailEntityExt();
        emailEntity.setEmail(req.getEmail());
        String data = "【中医诊所在线预约系统】验证码：" + verification + ", 您正在使用邮箱注册中医诊所在线预约系统\n"
                + "验证码有效期为" + giftProperties.getOverTime() + "分钟（若非本人操作,请删除此邮件）";
        emailEntity.setData(data);
        sendEmails.sendEmails(emailEntity);
    }

    /**
     * 医院申请注册
     * @param req
     */
    public void hospitalRegister(HospitalRegisterReq req) {
        checkEmail(req.getEmail());
        checkVerify(req.getEmail(),req.getVerify());
        List<HospitalMessageEntity> tmp = new ArrayList<>();
        Example example = new Example(HospitalMessageEntity.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("idCard",req.getIdCard()).andEqualTo("name",req.getName());
        tmp = hospitalMessageService.selectByExample(example);
        if (CollectionUtils.isNotEmpty(tmp)){
            throw new RuntimeException("此医院已经注册");
        }
        List<HospitalRegisterEntity> list = new ArrayList<>();
        example = new Example(HospitalRegisterEntity.class);
        criteria = example.createCriteria();
        criteria.andEqualTo("idCard",req.getIdCard());
        list = hospitalRegisterService.selectByExample(example);
        if(CollectionUtils.isNotEmpty(list)){
            throw new RuntimeException("你已经申请注册，请勿重复申请");
        }
        HospitalRegisterEntity hospitalRegisterEntity = new HospitalRegisterEntity();
        BeanUtils.copyProperties(req,hospitalRegisterEntity);
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append(req.getProvince() + "-");
        stringBuffer.append(req.getCity() + "-");
        if (StringUtils.isNotBlank(req.getArea())){
            stringBuffer.append(req.getArea() + "-");
        }
        stringBuffer.append(req.getTown() + " ");
        stringBuffer.append(req.getDetail());
        hospitalRegisterEntity.setAddress(stringBuffer.toString());
        hospitalRegisterEntity.setUuid(UUID.randomUUID().toString());
        hospitalRegisterService.insertSelective(hospitalRegisterEntity);
    }

    /**
     * 检查验证码
     * @param key
     */
    public void checkVerify(String key,String value){
        String verification = redisTemplate.opsForValue().get(key);
        if (StringUtils.isBlank((verification))){
            throw new RuntimeException("验证码已过期");
        }
        if (!verification.equals(value)){
            throw new RuntimeException("验证码错误");
        }
    }

    /**
     * 用户登录
     * @param req
     * @return
     */
    public LoginRsp login(UserLoginReq req) {
        LoginRsp loginRsp = new LoginRsp();
        Example example = new Example(UserEntity.class);
        Example.Criteria criteria = example.createCriteria();

        UserEntity user = null;
        if (StringUtils.isBlank(req.getExt())){
            criteria.andEqualTo("account",req.getAccount()).andEqualTo("password",req.getPassword()).andIsNull("ext");
            user = userService.selectOneByExample(example);
        }else{
            criteria.andEqualTo("account",req.getAccount()).andEqualTo("password",req.getPassword()).andIsNotNull("ext");
            List<UserEntity> userList = userService.selectByExample(example);
            if (CollectionUtils.isEmpty(userList)){
                throw new RuntimeException("用户名或密码错误");
            }
            for (UserEntity userEntity : userList) {
                try {
                    String hospitalUuid = JSONObject.parseObject(userEntity.getExt()).getString("hospitalUuid");
                    String hospitalUuidCompare = JSONObject.parseObject(req.getExt()).getString("hospitalUuid");
                    if (hospitalUuid.equals(hospitalUuidCompare)){
                        user = userEntity;
                    }
                }catch (Exception e){
                    throw new RuntimeException("用户名或密码错误");
                }

            }
        }

        if (user == null){
            throw new RuntimeException("用户名或密码错误");
        }
        switch (user.getType()){
            case "user":
                example = new Example(UserMessageEntity.class);
                criteria = example.createCriteria();
                criteria.andEqualTo("uuid",user.getUuid());
                UserMessageEntity userMessageEntity = userMessageService.selectOneByExample(example);
                loginRsp.setAge(getAgeFromIdCard(userMessageEntity.getIdCard()));
                loginRsp.setName(userMessageEntity.getName());
                loginRsp.setSex(userMessageEntity.getSex());
                loginRsp.setToken(generateToken(user,userMessageEntity.getName()));
                break;
            case "hospital":
                example = new Example(HospitalMessageEntity.class);
                criteria = example.createCriteria();
                criteria.andEqualTo("uuid",user.getUuid());
                HospitalMessageEntity hospitalMessageEntity = hospitalMessageService.selectOneByExample(example);
                loginRsp.setName(hospitalMessageEntity.getName());
                loginRsp.setToken(generateToken(user,hospitalMessageEntity.getName()));
                break;
            case "admin":
                String name = "管理员";
                loginRsp.setName(name);
                loginRsp.setToken(generateToken(user,name));
                break;
            case "medicine":
            case "frontDesk":
            case "doctor":
                example = new Example(DoctorEntity.class);
                criteria = example.createCriteria();
                criteria.andEqualTo("uuid",user.getUuid());
                DoctorEntity doctorEntity = doctorService.selectOneByExample(example);
                loginRsp.setSex(doctorEntity.getSex());
                loginRsp.setPictureUrl(doctorEntity.getPicture());
                loginRsp.setName(doctorEntity.getName());
                loginRsp.setDepartment(doctorEntity.getDepartment());
                loginRsp.setToken(generateToken(user, doctorEntity.getName()));
        }
        loginRsp.setType(user.getType());
        return loginRsp;
    }

    /**
     * 根据身份证计算当前年龄(精确到日)
     * @param idCard
     * @return
     */
    public Integer getAgeFromIdCard(String idCard) {
        int year =Integer.parseInt(idCard.substring(6,10));
        int mouth =Integer.parseInt(idCard.substring(10,12));
        int day =Integer.parseInt(idCard.substring(12,14));
        SimpleDateFormat formatter= new SimpleDateFormat("yyyyMMdd");
        Date date = new Date(System.currentTimeMillis());
        String nowDate = formatter.format(date);

        int nowYear = Integer.parseInt(nowDate.substring(0,4));
        int nowMonth = Integer.parseInt(nowDate.substring(4,6));
        int nowDay = Integer.parseInt(nowDate.substring(6,8));

        int result = nowYear - year;
        if(nowMonth == mouth){
            if(nowDay == day){
                return result;
            }else if(nowDay < day){
                return --result;
            }else{
                return result;
            }
        }else if(nowMonth < mouth){
            return --result;
        }else{
            return result;
        }
    }

    /**
     * 产生token
     * @param user
     * @param name
     * @return
     */
    public String generateToken(UserEntity user,String name){
        String token = null;
        if (StringUtils.isNotBlank(user.getExt())){
            token = redisTemplate.opsForValue().get(user.getAccount() + "-login" + user.getExt());
        } else {
            token = redisTemplate.opsForValue().get(user.getAccount() + "-login");
        }
        if (StringUtils.isNotBlank(token)){
            return token;
        }
        //Jwts.builder()生成
        //Jwts.parser()验证
        Claims claims = new DefaultClaims();
        claims.put("role",user.getType());
        claims.put("uuid",user.getUuid());
        claims.put("userID",user.getId());
        Calendar cd = Calendar.getInstance();
        cd.setTime(new Date());
        cd.add(Calendar.HOUR,hospitalProperties.getOverTime());
        Date newDate = cd.getTime();
        JwtBuilder jwtBuilder =  Jwts.builder()
                .setClaims(claims)
                .setSubject(name)//用户名
                .setIssuedAt(new Date())//登录时间
                .signWith(SignatureAlgorithm.HS256, TOKEN_SECRET).setExpiration(newDate);
        if (StringUtils.isNotBlank(user.getExt())){
            redisTemplate.opsForValue().set(user.getAccount() + "-login" + user.getExt(), jwtBuilder.compact(),hospitalProperties.getOverTime(),TimeUnit.HOURS);
        } else {
            redisTemplate.opsForValue().set(user.getAccount() + "-login", jwtBuilder.compact(),hospitalProperties.getOverTime(),TimeUnit.HOURS);
        }
        return jwtBuilder.compact();
    }

    /**
     * 验证邮箱
     * @param email
     * @param
     */
    public void checkEmail(String email){
        Example example = new Example(UserEntity.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("account",email);
        List<UserEntity> userEntities = userService.selectByExample(example);
        if (!CollectionUtils.isEmpty(userEntities)){
            throw new RuntimeException("此邮箱已注册");
        }
    }

    /**
     * 用户注销
     * @param req
     */
    public void deleteCount(DeleteCountReq req) {
        Example example = new Example(UserEntity.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("uuid",req.getUuid());
        if (StringUtils.isNotBlank(req.getExt())) {
            criteria.andEqualTo("ext",req.getExt());
        }
        userService.deleteByExample(example);
    }
}
